package org.peterf.foxish.buffer;

import java.nio.Buffer;

import org.peterf.foxish.opengl20.OpenGLUtil;
import org.peterf.foxish.opengl20.OpenGLUtil.BufferUsage;
import org.peterf.foxish.opengl20.OpenGLUtil.Type;

/**
 * This maintains a {@link Buffer} used as index buffer. Extends this to decide
 * the {@link Buffer} type and provide more flexibility. Subclass must set
 * {@link #data} properly upon construction. If a VBO is wanted,
 * {@link #upload()} should also be called.
 * 
 * @author peter
 * 
 */
public abstract class IndexBuffer {

    /**
     * The {@link Buffer} reference of the contents.
     */
    protected Buffer data = null;

    /**
     * The name of the VBO.
     */
    protected int name = 0;

    /**
     * Size in bytes of the buffer.
     */
    protected int size;

    /**
     * Hint of the buffer usage.
     */
    protected BufferUsage usage;

    /**
     * Construct an index buffer with certain size and usage. Note that this
     * method does not allocate any data, instead, subclasses should set
     * {@link #data} properly to reference the actual data storage.
     * 
     * @param size
     *            Size in bytes of the buffer size.
     * @param usage
     *            Hint of the buffer usage.
     */
    protected IndexBuffer(int size, BufferUsage usage) {
        this.size = size;
        this.usage = usage;
    }

    /**
     * Delete the possible resource held by VBO. If there is no VBO holding our
     * data, this method has no effect.
     */
    public void delete() {
        if (name != 0) {
            OpenGLUtil.deleteBuffer(name);
        }
    }

    /**
     * 
     * @return The {@link Buffer} this maintains.
     */
    public Buffer getData() {
        return data;
    }

    /**
     * 
     * @return The data type of the buffer.
     */
    public abstract Type getType();

    /**
     * 
     * @return The usage hint.
     */
    public BufferUsage getUsage() {
        return usage;
    }

    /**
     * 
     * @return Whether there exists a VBO storing our data.
     */
    public boolean hasVBO() {
        return name != 0;
    }

    /**
     * Try to create a VBO for our storage and upload the contents. This is used
     * when the OpenGL context-related resources are to be loaded or reloaded.
     */
    public void upload() {
        int b = OpenGLUtil.createBuffer();
        if (b != 0) {
            OpenGLUtil.bindIndexBuffer(b);
            if (!OpenGLUtil.uploadIndexBuffer(size, data, usage)) {
                OpenGLUtil.deleteBuffer(b);
                b = 0;
            }
        }
        name = b;
    }

    /**
     * Set this buffer the current index buffer.
     */
    public void use() {
        OpenGLUtil.bindIndexBuffer(name);
    }

}
